﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CCL.SocketMessage
{
    /// <summary>
    /// 직렬화 가능한 Message를 제공합니다.
    /// </summary>
    public class Message : ISerializable
    {
        /// <summary>
        /// 직렬화 가능한 Header를 가져오거나 설정합니다.
        /// </summary>
        public Header Header { get; set; }

        /// <summary>
        /// 직렬화 가능한 Body를 가져오거나 설정합니다.
        /// </summary>
        public Body Body { get; set; }

        /// <summary>
        /// 바이트 배열로 직렬화 합니다.
        /// </summary>
        /// <returns>직렬화된 바이트 배열</returns>
        public byte[] GetByte()
        {
            byte[] bytes = new byte[GetSize()];

            Header.GetByte().CopyTo(bytes, 0);
            Body.GetByte().CopyTo(bytes, Header.GetSize());

            return bytes;
        }

        /// <summary>
        /// 직렬화 가능한 객체의 바이트 사이즈를 가져옵니다.
        /// </summary>
        /// <returns>직렬화된 바이트 사이즈</returns>
        public uint GetSize()
        {
            return Header.GetSize() + Body.GetSize();
        }

        /// <summary>
        /// 서버로 요청하는 Message를 만들어 줍니다.
        /// </summary>
        /// <param name="body">만들고자 하는 Message의 본문</param>
        /// <returns>만들어진 Message</returns>
        static public Message MessageRequestBuilder(Body body)
        {
            Message msg = new Message();
            msg.Body = body;
            msg.Header = new Header()
            {
                BodyLength = body.GetSize(),
                Fragmented = Constant.Fragmented.No,
                LastMsg = Constant.LastMsg.Yes,
                MsgId = 0,
                SEQ = 0,
                BodyType = Constant.TypeConverter(body),
                HeaderType = Constant.HeaderType.Requst
            };

            return msg;
        }

        // [추가시 수정 必]
        /// <summary>
        /// 서버에서 응답하는 Message를 만들어 줍니다.
        /// </summary>
        /// <param name="header">만들고자 하는 Message의 Header</param>
        /// <param name="bodyBytes">직렬화 가능한 Body의 byte 배열</param>
        /// <returns>만들어진 Message</returns>
        static public Message MessageResponseBuilder(Header header, byte[] bodyBytes)
        {
            Message msg = new Message();
            msg.Header = header;

            Body body = null;

            switch (header.BodyType)
            {
                case Constant.BodyType.Login:
                    body = new Response.Login(bodyBytes);
                    break;
                case Constant.BodyType.Join:
                    body = new Response.Join(bodyBytes);
                    break;
                case Constant.BodyType.RegistProject:
                    body = new Response.RegistProject(bodyBytes);
                    break;
                case Constant.BodyType.GetProjectList:
                    body = new Response.GetProjectList(bodyBytes);
                    break;
                case Constant.BodyType.GetProjectMemberList:
                    body = new Response.GetProjectMemberList(bodyBytes);
                    break;
                case Constant.BodyType.RegistProjectMemberList:
                    body = new Response.RegistProjectMemberList(bodyBytes);
                    break;
                case Constant.BodyType.FileDownloadReady:
                    body = new Response.FileDownloadReady(bodyBytes);
                    break;
                case Constant.BodyType.FileDownload:
                    body = new Response.FileDownload(bodyBytes);
                    break;
                case Constant.BodyType.FileUpload:
                    body = new Response.FileUpload(bodyBytes);
                    break;
                case Constant.BodyType.CommitProject:
                    body = new Response.CommitProject(bodyBytes);
                    break;
                case Constant.BodyType.ShowLog:
                    body = new Response.ShowLog(bodyBytes);
                    break;
                default:
                    throw new Exception("Response 할 수 없는 Type을 인스턴스화 시도하였습니다.");

                // 미구현
            }

            msg.Body = body;

            return msg;
        }

        /// <summary>
        /// 서버에서 응답하는 Message를 만들어 줍니다.
        /// </summary>
        /// <param name="body">만들고자 하는 Message의 본문</param>
        /// <returns>만들어진 Message</returns>
        static public Message MessageResponseBuilder(Body body)
        {
            Message msg = new Message();
            msg.Body = body;
            msg.Header = new Header()
            {
                BodyLength = body.GetSize(),
                Fragmented = Constant.Fragmented.No,
                LastMsg = Constant.LastMsg.Yes,
                MsgId = 0,
                SEQ = 0,
                BodyType = Constant.TypeConverter(body),
                HeaderType = Constant.HeaderType.Response
            };

            return msg;
        }
    }
}
